/*!
 * \file util.h
 *
 * \brief Utilities for the IEGen project
 *
 * \date Started: 9/13/2010
 * \date Last Modified: 9/13/2010
 * \authors Alan LaMielle
 *
 * Copyright (c) 2010, Colorado State University <br>
 * All rights reserved. <br>
 * See ../../COPYING for details. <br>
 */
#ifndef UTIL_H_
#define UTIL_H_

#include <iegenlib/iegenlib.h>

#include <exception>
using std::exception;
#include <string>
using std::string;
#include <set>
using std::set;
#include <list>
using std::list;
#include <map>
using std::map;
#include <sstream>
using std::stringstream;

namespace iegenlib{

class StringException: public exception {
public:
  inline StringException(string s):err(s) {};

  inline ~StringException() throw() {};

  inline const char* what() const throw() {
    return err.c_str();
  }

private:
  string err;
};

class ParseException : public StringException {
public:
   inline ParseException(string s) : StringException(s) {}
};

class EntityNotFound : public StringException{
public:
   inline EntityNotFound(string s) : StringException(s) {}
};

class EntityExists : public StringException{
public:
   inline EntityExists(string s) : StringException(s) {}
};

class ComposeException : public StringException{
public:
   inline ComposeException(string s) : StringException(s) {}
};

class ApplyException : public StringException{
public:
   inline ApplyException(string s) : StringException(s) {}
};

class UnionException : public StringException{
public:
   inline UnionException(string s) : StringException(s) {}
};

class OperatorEqualsException : public StringException{
public:
    inline OperatorEqualsException(string s) : StringException(s) {}
};

/*!
 * A unique name created from the base name and the set of names that
 * are already in use
 * @param name The base name to create the unique name from
 * @param taken The set of names that are already in use
 * @return the unique name that is created from base name and the taken names
 */
string createUniqueName(string name, set<string> taken);

/*!
 * Returns a list of new names based on the given sequence of names.  Unique
 * names are created based on the given reserved names.  A mapping is
 * maintained from old to new names.
 *
 * @param begin start of the sequence of names
 * @param end end of the sequence of names
 * @param taken set of reserved names
 * @param old2new mapping of old names to new names
 * @return the list of unique names
 */
list<string> createUniqueNames(list<string>::const_iterator begin,
                              list<string>::const_iterator end,
                              set<string>& taken,
                              map<string,string>& old2new);

/*!
 * Fills the given old2new mapping to make the given names sequence match the
 * given sequence to match.
 *
 * @param begin_match start of the sequence of names match
 * @param end_match end of the sequence of names to match
 * @param name_start start of the sequence of names to make match
 * @param name_end end of the sequence of names to make match
 * @param old2new mapping of old names to new names
 */
void createMatchingNames(list<string>::const_iterator match_begin,
                         list<string>::const_iterator match_end,
                         list<string>::const_iterator names_begin,
                         list<string>::const_iterator names_end,
                         map<string,string>& old2new);

/*!
* Creates a unioned set of the two given lists of names.
*
* @param l1 the first list
* @param l2 the second list
* @return the unioned set
*/
set<string> unionNamesLists(list<string> const& l1,list<string> const& l2);

/*!
* Creates a new list of TupleTypes where the variables have been renamed using
* the given rename mapping.
*
* @param begin the start of the sequence of TupleTypes
* @param end the end of the sequence of TupleTypes
* @return the new list of TupleTypes
*/
list<TupleType> renameTupleVars(list<TupleType>::const_iterator begin,
                                list<TupleType>::const_iterator end,
                                map<string,string> renameMap);
}//end namespace iegenlib

#endif
